home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / g__~1 / gplibs17.zoo / streambu.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-02  |  15.8 KB  |  731 lines

  1. //    This is part of the iostream library, providing input/output for C++.
  2. //    Copyright (C) 1991, 1992 Per Bothner.
  3. //
  4. //    This library is free software; you can redistribute it and/or
  5. //    modify it under the terms of the GNU Library General Public
  6. //    License as published by the Free Software Foundation; either
  7. //    version 2 of the License, or (at your option) any later version.
  8. //
  9. //    This library is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. //    Library General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU Library General Public
  15. //    License along with this library; if not, write to the Free
  16. //    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #define _STREAM_COMPAT
  19. #ifdef __GNUG__
  20. #pragma implementation
  21. #endif
  22. #include <ioprivat.h>
  23. #include <string.h>
  24.  
  25. void streambuf::_un_link()
  26. {
  27.     if (_flags & _S_LINKED) {
  28.     streambuf **f;
  29.     for (f = &_list_all; *f != NULL; f = &(*f)->xchain()) {
  30.         if (*f == this) {
  31.         *f = xchain();
  32.         break;
  33.         }
  34.     }
  35.     _flags &= ~_S_LINKED;
  36.     }
  37. }
  38.  
  39. void streambuf::_link_in()
  40. {
  41.     if ((_flags & _S_LINKED) == 0) {
  42.     _flags |= _S_LINKED;
  43.     xchain() = _list_all;
  44.     _list_all = this;
  45.     }
  46. }
  47.  
  48. // Return minimum _pos markers
  49. // Assumes the current get area is the main get area.
  50. long streambuf::_least_marker()
  51. {
  52.     long least_so_far = _egptr - _eback;
  53.     for (register streammarker *mark = _markers;
  54.      mark != NULL; mark = mark->_next)
  55.     if (mark->_pos < least_so_far)
  56.         least_so_far = mark->_pos;
  57.     return least_so_far;
  58. }
  59.  
  60. // Switch current get area from backup buffer to (start of) main get area.
  61.  
  62. void streambuf::switch_to_main_get_area()
  63. {
  64.     char *tmp;
  65.     _flags &= ~_S_IN_BACKUP;
  66.     // Swap _egptr and _other_egptr.
  67.     tmp= _egptr; _egptr= _other_egptr; _other_egptr= tmp;
  68.     // Swap _eback and _other_gbase.    
  69.     tmp= _eback; _eback = _other_gbase; _other_gbase = tmp;
  70.     _gptr = _eback;
  71. }
  72.  
  73. // Switch current get area from main get area to (end of) backup area.
  74.  
  75. void streambuf::switch_to_backup_area()
  76. {
  77.     char *tmp;
  78.     _flags |= _S_IN_BACKUP;
  79.     // Swap _egptr and _other_egptr.
  80.     tmp = _egptr; _egptr = _other_egptr; _other_egptr = tmp;
  81.     // Swap _gbase and _other_gbase.    
  82.     tmp = _eback; _eback = _other_gbase; _other_gbase = tmp;
  83.     _gptr = _egptr;
  84. }
  85.  
  86. int streambuf::switch_to_get_mode()
  87. {
  88.     if (_pptr > _pbase)
  89.     if (overflow(EOF) == EOF)
  90.         return EOF;
  91.     if (in_backup()) {
  92.     _eback = _aux_limit;
  93.     }
  94.     else {
  95.     _eback = _base;
  96.     if (_pptr > _egptr)
  97.         _egptr = _pptr;
  98.     }
  99.     _gptr = _pptr;
  100.  
  101.     setp(_gptr, _gptr);
  102.  
  103.     _flags &= ~_S_CURRENTLY_PUTTING;
  104.     return 0;
  105. }
  106.  
  107. void streambuf::free_backup_area()
  108. {
  109.     if (in_backup())
  110.     switch_to_main_get_area();  // Just in case.
  111.     delete [] _other_gbase;
  112.     _other_gbase = NULL;
  113.     _other_egptr = NULL;
  114.     _aux_limit = NULL;
  115. }
  116.  
  117. #if 0
  118. int streambuf::switch_to_put_mode()
  119. {
  120.     _pbase = _gptr;
  121.     _pptr = _gptr;
  122.     _epptr = in_backup() ? _egptr : _ebuf; // wrong if line- or un-buffered?
  123.  
  124.     _gptr = _egptr;
  125.     _eback = _egptr;
  126.  
  127.     _flags |= _S_CURRENTLY_PUTTING;
  128.     return 0;
  129. }
  130. #endif
  131.  
  132. #ifdef _G_FRIEND_BUG
  133. int __underflow(register streambuf *sb) { return __UNDERFLOW(sb); }
  134. int __UNDERFLOW(register streambuf *sb)
  135. #else
  136. int __underflow(register streambuf *sb)
  137. #endif
  138. {
  139.     if (sb->put_mode())
  140.         if (sb->switch_to_get_mode() == EOF) return EOF;
  141.     if (sb->_gptr < sb->_egptr)
  142.     return *(unsigned char*)sb->_gptr;
  143.     if (sb->in_backup()) {
  144.     sb->switch_to_main_get_area();
  145.     if (sb->_gptr < sb->_egptr)
  146.         return *sb->_gptr;
  147.     }
  148.     if (sb->have_markers()) {
  149.     // Append [_gbase.._egptr] to backup area.
  150.     long least_mark = sb->_least_marker();
  151.     // needed_size is how much space we need in the backup area.
  152.     long needed_size = (sb->_egptr - sb->_eback) - least_mark;
  153.     long current_Bsize = sb->_other_egptr - sb->_other_gbase;
  154.     long avail; // Extra space available for future expansion.
  155.     if (needed_size > current_Bsize) {
  156.         avail = 0; // 100 ?? FIXME
  157.         char *new_buffer = new char[avail+needed_size];
  158.         if (least_mark < 0) {
  159.         memcpy(new_buffer + avail,
  160.                sb->_other_egptr + least_mark,
  161.                -least_mark);
  162.         memcpy(new_buffer +avail - least_mark,
  163.                sb->_eback,
  164.                sb->_egptr - sb->_eback);
  165.         }
  166.         else
  167.         memcpy(new_buffer + avail,
  168.                sb->_eback + least_mark,
  169.                needed_size);
  170.         delete [] sb->_other_gbase;
  171.         sb->_other_gbase = new_buffer;
  172.         sb->_other_egptr = new_buffer + avail + needed_size;
  173.     }
  174.     else {
  175.         avail = current_Bsize - needed_size;
  176.         if (least_mark < 0) {
  177.         memmove(sb->_other_gbase + avail,
  178.             sb->_other_egptr + least_mark,
  179.             -least_mark);
  180.         memcpy(sb->_other_gbase + avail - least_mark,
  181.                sb->_eback,
  182.                sb->_egptr - sb->_eback);
  183.         }
  184.         else if (needed_size > 0)
  185.         memcpy(sb->_other_gbase + avail,
  186.                sb->_eback + least_mark,
  187.                needed_size);
  188.     }
  189.     // FIXME: Dubious arithmetic if pointers are NULL
  190.     sb->_aux_limit = sb->_other_gbase + avail;
  191.     // Adjust all the streammarkers.
  192.     long delta = sb->_egptr - sb->_eback;
  193.     for (register streammarker *mark = sb->_markers;
  194.          mark != NULL; mark = mark->_next)
  195.         mark->_pos -= delta;
  196.     }
  197.     else if (sb->have_backup())
  198.     sb->free_backup_area();
  199.     return sb->underflow();
  200. }
  201.  
  202. #ifdef _G_FRIEND_BUG
  203. int __overflow(register streambuf *sb, int c) { return __OVERFLOW(sb, c); }
  204. int __OVERFLOW(register streambuf *sb, int c)
  205. #else
  206. int __overflow(streambuf* sb, int c)
  207. #endif
  208. {
  209.     return sb->overflow(c);
  210. }
  211.  
  212. #ifdef atarist
  213. // for the atari we take a hit here so that bin/text modes are taken care of
  214. // automatically by sputc/sbumpc
  215.  
  216. _G_size_t streambuf::xsputn(const char* s, _G_size_t n) // OPTIMIZE THIS!
  217. {
  218.     size_t count = 0;
  219.  
  220.     if(((long)n) < 0) return 0;
  221.  
  222.     for (; count < n; count++) {
  223.     if (sputc(*s++) == EOF)
  224.         break;
  225.     }
  226.     return count;
  227. }
  228.  
  229. _G_size_t streambuf::xsgetn(char* s, _G_size_t n) // OPTIMIZE THIS!
  230. {
  231.     size_t count = 0;
  232.     for (; count < n; count++) {
  233.     int ch = sbumpc();
  234.     if (ch == EOF)
  235.         break;
  236.     *s++ = ch;
  237.     }
  238.     return count;
  239. }
  240.  
  241. _G_size_t streambuf::ignore(_G_size_t n)
  242. {
  243.     size_t more = n;
  244.     int ch;
  245.  
  246.     while(more && ((ch = sbumpc() != EOF))) more--;
  247.     return n - more;
  248. }
  249.  
  250. #else
  251.  
  252. _G_size_t streambuf::xsputn(register const char* s, _G_size_t n)
  253. {
  254.     if ((long)n <= 0)
  255.     return 0;
  256.     register _G_size_t more = n;
  257.     for (;;) {
  258.     long count = _epptr - _pptr; // Space available.
  259.     if (count > 0) {
  260.         if (count > more)
  261.         count = more;
  262.         if (count > 20) {
  263.         memcpy(_pptr, s, count);
  264.         s += count;
  265.         _pptr += count;
  266.         }
  267.         else if (count <= 0)
  268.         count = 0;
  269.         else {
  270.         register char *p = _pptr;
  271.         for (register long i = count; --i >= 0; ) *p++ = *s++;
  272.         _pptr = p;
  273.         }
  274.         more -= count;
  275.     }
  276.     if (more == 0 || __overflow(this, (unsigned char)*s++) == EOF)
  277.         break;
  278.     more--;
  279.     }
  280.     return n - more;
  281. }
  282.  
  283.  
  284. _G_size_t streambuf::xsgetn(char* s, _G_size_t n)
  285. {
  286.     register _G_size_t more = n;
  287.     for (;;) {
  288.     long count = _egptr - _gptr; // Data available.
  289.     if (count > 0) {
  290.         if (count > more)
  291.         count = more;
  292.         if (count > 20) {
  293.         memcpy(s, _gptr, count);
  294.         s += count;
  295.         _gptr += count;
  296.         }
  297.         else if (count <= 0)
  298.         count = 0;
  299.         else {
  300.         register char *p = _gptr;
  301.         for (register long i = count; --i >= 0; ) *s++ = *p++;
  302.         _gptr = p;
  303.         }
  304.         more -= count;
  305.     }
  306.     if (more == 0 || __underflow(this) == EOF)
  307.         break;
  308.     }
  309.     return n - more;
  310. }
  311.  
  312. _G_size_t streambuf::ignore(_G_size_t n)
  313. {
  314.     register _G_size_t more = n;
  315.     for (;;) {
  316.     int long = _egptr - _gptr; // Data available.
  317.     if (count > 0) {
  318.         if (count > more)
  319.         count = more;
  320.         _gptr += count;
  321.         more -= count;
  322.     }
  323.     if (more == 0 || __underflow(this) == EOF)
  324.         break;
  325.     }
  326.     return n - more;
  327. }
  328. #endif
  329.  
  330. int streambuf::padn(char pad, _G_size_t count)
  331. {
  332. #define PADSIZE 16
  333.     static char const blanks[PADSIZE] =
  334.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  335.     static char const zeroes[PADSIZE] =
  336.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  337.     char padbuf[PADSIZE];
  338.     const char *padptr;
  339.     register long i;
  340.     
  341.     if (pad == ' ')
  342.     padptr = blanks;
  343.     else if (pad == '0')
  344.     padptr = zeroes;
  345.     else {
  346.     for (i = PADSIZE; --i >= 0; ) padbuf[i] = pad;
  347.     padptr = padbuf;
  348.     }
  349.     for (i = count; i >= PADSIZE; i -= PADSIZE)
  350.     if (sputn(padptr, PADSIZE) != PADSIZE)
  351.         return EOF;
  352.     if (i > 0 && sputn(padptr, i) != i)
  353.     return EOF;
  354.     return pad;
  355. }
  356.  
  357. int streambuf::sync()
  358. {
  359.     if (gptr() == egptr() && pptr() == pbase())
  360.     return 0;
  361.     return EOF;
  362. }
  363.  
  364. int streambuf::pbackfail(int c)
  365. {
  366.     if (_gptr > _eback)
  367.     _gptr--;
  368.     else if (seekoff(-1, ios::cur, ios::in) == EOF)
  369.     return EOF;
  370.     if (c != EOF && *_gptr != c)
  371.     *_gptr = c;
  372.     return (unsigned char)c;
  373. }
  374.  
  375. streambuf* streambuf::setbuf(char* p, _G_size_t len)
  376. {
  377.     if (sync() == EOF)
  378.     return NULL;
  379.     if (p == NULL || len == 0) {
  380.     unbuffered(1);
  381.     setb(_shortbuf, _shortbuf+1, 0);
  382.     }
  383.     else {
  384.     unbuffered(0);
  385.     setb(p, p+len, 0);
  386.     }
  387.     setp(0, 0);
  388.     setg(0, 0, 0);
  389.     return this;
  390. }
  391.  
  392. streampos streambuf::seekpos(streampos pos, int mode)
  393. {
  394.     return seekoff(pos, ios::beg, mode);
  395. }
  396.  
  397. void streambuf::setb(char* b, char* eb, int a)
  398. {
  399.     if (_base && !(_flags & _S_USER_BUF))
  400.     FREE_BUF(_base);
  401.     _base = b;
  402.     _ebuf = eb;
  403.     if (a)
  404.     _flags &= ~_S_USER_BUF;
  405.     else
  406.     _flags |= _S_USER_BUF;
  407. }
  408.  
  409. #ifdef atarist
  410. extern "C" { extern unsigned long __DEFAULT_BUFSIZ__; }
  411.  
  412. int streambuf::doallocate()
  413. {
  414.     char *buf = (char *)malloc((size_t)__DEFAULT_BUFSIZ__);
  415.     if (buf == NULL)
  416.     return EOF;
  417.     setb(buf, buf+__DEFAULT_BUFSIZ__, 1);
  418.     return 1;
  419. }
  420. #else
  421. int streambuf::doallocate()
  422. {
  423.     char *buf = ALLOC_BUF(_G_BUFSIZ);
  424.     if (buf == NULL)
  425.     return EOF;
  426.     setb(buf, buf+_G_BUFSIZ, 1);
  427.     return 1;
  428. }
  429. #endif
  430.  
  431. void streambuf::doallocbuf()
  432. {
  433.     if (base() || (!unbuffered() && doallocate() != EOF)) return;
  434.     setb(_shortbuf, _shortbuf+1, 0);
  435. }
  436.  
  437. #ifdef atarist
  438. extern "C" int __default_mode__;
  439. #endif
  440.  
  441. streambuf::streambuf(unsigned long flags)
  442. {
  443. #ifdef atarist
  444.   if(!(flags & _IOS_TEXT))
  445.       _flags = _IO_MAGIC | ((__default_mode__)? _S_IS_BINARY : 0) | flags;
  446.   else
  447.       _flags = _IO_MAGIC | (flags & (~_S_IS_BINARY));
  448. #else
  449.   _flags = _IO_MAGIC|flags;
  450. #endif
  451.   _base = NULL;
  452.   _ebuf = NULL;
  453.   _eback = NULL;
  454.   _gptr = NULL;
  455.   _egptr = NULL;
  456.   _pbase = NULL;
  457.   _pptr = NULL;
  458.   _epptr = NULL;
  459.   _chain = NULL; // Not necessary.
  460.  
  461.   _other_gbase = NULL;
  462.   _aux_limit = NULL;
  463.   _other_egptr = NULL;
  464.   _markers = NULL;
  465.   _cur_column = 0;
  466. }
  467.  
  468. streambuf::~streambuf()
  469. {
  470.     if (_base && !(_flags & _S_USER_BUF))
  471.     FREE_BUF(_base);
  472.  
  473.     for (register streammarker *mark = _markers;
  474.      mark != NULL; mark = mark->_next)
  475.     mark->_sbuf = NULL;
  476.     
  477. }
  478.  
  479. streampos
  480. streambuf::seekoff(streamoff, _seek_dir, int mode /*=ios::in|ios::out*/)
  481. {
  482.     return EOF;
  483. }
  484.  
  485. int streambuf::sputbackc(char c)
  486. {
  487.     if (_gptr > _eback && (unsigned char)_gptr[-1] == (unsigned char)c) {
  488.     _gptr--;
  489.     return (unsigned char)c;
  490.     }
  491.     return pbackfail(c);
  492. }
  493.  
  494. int streambuf::sungetc()
  495. {
  496.     if (_gptr > _eback) {
  497.     _gptr--;
  498.     return (unsigned char)*_gptr;
  499.     }
  500.     else
  501.     return pbackfail(EOF);
  502. }
  503.  
  504. #if 0 /* Work in progress */
  505. void streambuf::collumn(int c)
  506. {
  507.     if (c == -1)
  508.     _collumn = -1;
  509.     else
  510.     _collumn = c - (_pptr - _pbase);
  511. }
  512. #endif
  513.  
  514.  
  515. int streambuf::get_column()
  516. {
  517.     if (_cur_column) 
  518.     return __adjust_column(_cur_column - 1, pbase(), pptr() - pbase());
  519.     return -1;
  520. }
  521.  
  522. int streambuf::set_column(int i)
  523. {
  524.     _cur_column = i+1;
  525.     return 0;
  526. }
  527.  
  528. int streambuf::flush_all()
  529. {
  530.     int result = 0;
  531.     for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain())
  532.     if (sb->overflow(EOF) == EOF)
  533.         result = EOF;
  534.     return result;
  535. }
  536.  
  537. void streambuf::flush_all_linebuffered()
  538. {
  539.     for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain())
  540.     if (sb->linebuffered())
  541.         sb->overflow(EOF);
  542. }
  543.  
  544. int backupbuf::underflow()
  545. {
  546.     return EOF;
  547. }
  548.  
  549. int backupbuf::overflow(int c)
  550. {
  551.     return EOF;
  552. }
  553.  
  554. streammarker::streammarker(streambuf *sb)
  555. {
  556.     _sbuf = sb;
  557.     if (!(sb->xflags() & _S_IS_BACKUPBUF)) {
  558.     set_streampos(sb->seekoff(0, ios::cur, ios::in));
  559.     _next = 0;
  560.     }
  561.     else {
  562.     if (sb->put_mode())
  563.         sb->switch_to_get_mode();
  564.     if (((backupbuf*)sb)->in_backup())
  565.         set_offset(sb->_gptr - sb->_egptr);
  566.     else
  567.         set_offset(sb->_gptr - sb->_eback);
  568.  
  569.     // Should perhaps sort the chain?
  570.     _next = ((backupbuf*)sb)->_markers;
  571.     ((backupbuf*)sb)->_markers = this;
  572.     }
  573. }
  574.  
  575. streammarker::~streammarker()
  576. {
  577.     if (saving()) {
  578.     // Unlink from sb's chain.
  579.     register streammarker **ptr = &((backupbuf*)_sbuf)->_markers;
  580.     for (; ; ptr = &(*ptr)->_next)
  581.         if (*ptr == NULL)
  582.         break;
  583.         else if (*ptr == this) {
  584.         *ptr = _next;
  585.         return;
  586.         }
  587.     }
  588. #if 0
  589.     if _sbuf has a backup area that is no longer needed, should we delete
  590.     it now, or wait until underflow()?
  591. #endif
  592. }
  593.  
  594. #define BAD_DELTA EOF
  595.  
  596. int streammarker::delta(streammarker& other_mark)
  597. {
  598.     if (_sbuf != other_mark._sbuf)
  599.     return BAD_DELTA;
  600.     if (saving() && other_mark.saving())
  601.     return _pos - other_mark._pos;
  602.     else if (!saving() && !other_mark.saving())
  603.     return _spos - other_mark._spos;
  604.     else
  605.     return BAD_DELTA;
  606. }
  607.  
  608. int streammarker::delta()
  609. {
  610.     if (_sbuf == NULL)
  611.     return BAD_DELTA;
  612.     if (saving()) {
  613.     int cur_pos;
  614.     if (_sbuf->in_backup())
  615.         cur_pos = _sbuf->_gptr - _sbuf->_egptr;
  616.     else
  617.         cur_pos = _sbuf->_gptr - _sbuf->_eback;
  618.     return _pos - cur_pos;
  619.     }
  620.     else {
  621.     if (_spos == EOF)
  622.         return BAD_DELTA;
  623.     int cur_pos = _sbuf->seekoff(0, ios::cur);
  624.     if (cur_pos == EOF)
  625.         return BAD_DELTA;
  626.     return _pos - cur_pos;
  627.     }
  628. }
  629.  
  630. int streambuf::seekmark(streammarker& mark, long delta /* = 0 */)
  631. {
  632.     if (mark._sbuf != this)
  633.     return EOF;
  634.     if (!mark.saving()) {
  635.     return seekpos(mark._spos, ios::in);
  636.     }
  637.     else if (mark._pos >= 0) {
  638.     if (in_backup())
  639.         switch_to_main_get_area();
  640.     _gptr = _eback + mark._pos;
  641.     }
  642.     else {
  643.     if (!in_backup())
  644.         switch_to_backup_area();
  645.     _gptr = _egptr + mark._pos;
  646.     }
  647.     return 0;
  648. }
  649.  
  650. void streambuf::unsave_markers()
  651. {
  652.     register streammarker *mark =_markers;
  653.     if (_markers) {
  654.     streampos offset = seekoff(0, ios::cur, ios::in);
  655.     if (offset != EOF) {
  656.         offset += eGptr() - Gbase();
  657.         for ( ; mark != NULL; mark = mark->_next)
  658.         mark->set_streampos(mark->_pos + offset);
  659.     }
  660.     else {
  661.         for ( ; mark != NULL; mark = mark->_next)
  662.         mark->set_streampos(EOF);
  663.     }
  664.     _markers = 0;
  665.     }
  666.  
  667.     free_backup_area();
  668. }
  669.  
  670. int backupbuf::pbackfail(int c)
  671. {
  672.     // Need to handle a filebuf in write mode (switch to read mode).  FIXME!
  673.  
  674.     if (have_backup() && !in_backup()) {
  675.     switch_to_backup_area();
  676.     }
  677.     if (!have_backup()) {
  678.     // No backup buffer: allocate one.
  679.     // Use short buffer, if unused? (probably not)  FIXME 
  680.     int backup_size = 128;
  681.     _other_gbase = new char [backup_size];
  682.     _other_egptr = _other_gbase + backup_size;
  683.     _aux_limit = _other_egptr;
  684.     switch_to_backup_area();
  685.     }
  686.     else if (gptr() <= eback()) {
  687.     // Increase size of existing backup buffer.
  688.     size_t new_size;
  689.     size_t old_size = egptr() - eback();
  690.     new_size = 2 * old_size;
  691.     char* new_buf = new char [new_size];
  692.     memcpy(new_buf+(new_size-old_size), eback(), old_size);
  693.     delete [] eback();
  694.     setg(new_buf, new_buf+(new_size-old_size), new_buf+new_size);
  695.     _aux_limit = _gptr;
  696.     }
  697.     _gptr--;
  698.     if (c != EOF && *_gptr != c)
  699.     *_gptr = c;
  700.     return (unsigned char)*_gptr;
  701. }
  702.  
  703. unsigned __adjust_column(unsigned start, const char *line, int count)
  704. {
  705.     register const char *ptr = line + count;
  706.     while (ptr > line)
  707.     if (*--ptr == '\n')
  708.         return line + count - ptr - 1;
  709.     return start + count;
  710. }
  711.  
  712. int ios::readable() { return !(rdbuf()->_flags & _S_NO_READS); }
  713. int ios::writable() { return !(rdbuf()->_flags & _S_NO_WRITES); }
  714. int ios::is_open() { return rdbuf()
  715.              && (rdbuf()->_flags & _S_NO_READS+_S_NO_WRITES)
  716.                  != _S_NO_READS+_S_NO_WRITES; }
  717.  
  718. #if defined(linux)
  719. #define IO_CLEANUP ;
  720. #endif
  721.  
  722. #ifdef IO_CLEANUP
  723.   IO_CLEANUP
  724. #else
  725. struct __io_defs {
  726.     __io_defs() { }
  727.     ~__io_defs() { streambuf::flush_all(); }
  728. };   
  729. __io_defs io_defs__;
  730. #endif
  731.